package com.dd.cloud.user.service.agent.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dd.cloud.common.config.common.ProfilesProperties;
import com.dd.cloud.common.constants.*;
import com.dd.cloud.user.entity.admin.AdminSaleInfo;
import com.dd.cloud.user.entity.admin.SaleInviteAgent;
import com.dd.cloud.user.entity.agent.Agent;
import com.dd.cloud.common.interceptor.UserInterceptor;
import com.dd.cloud.user.entity.agent.AgentUser;
import com.dd.cloud.user.mapper.agent.AgentMapper;
import com.dd.cloud.user.req.agent.*;
import com.dd.cloud.user.res.agent.*;
import com.dd.cloud.user.service.admin.IAdminSaleInfoService;
import com.dd.cloud.user.service.admin.ISaleInviteAgentService;
import com.dd.cloud.user.service.agent.IAgentService;
import com.dd.cloud.user.service.agent.IAgentUserService;
import com.dd.cloud.common.vo.LoginInfo;
import com.dd.cloud.common.config.sms.SmsComponent;
import com.dd.cloud.common.exception.ZekeException;
import com.dd.cloud.common.utils.Assert;
import com.dd.cloud.common.utils.BigDecimalUtils;
import com.dd.cloud.common.utils.DateUtils;
import com.dd.cloud.common.utils.SerialNumberUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author Lx
 * @version 1.0
 */
@Slf4j
@Service
public class AgentServiceImpl extends ServiceImpl<AgentMapper, Agent> implements IAgentService {
    @Autowired
    private SmsComponent smsComponent;
    @Autowired
    private IAgentUserService agentUserService;
    @Autowired
    private IAdminSaleInfoService adminSaleInfoService;
    @Autowired
    private ISaleInviteAgentService saleInviteAgentService;
    @Autowired
    private ProfilesProperties profilesProperties;

    /**
     * 创建代理商
     *
     * @param req
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createAgent(AgentCreateReq req) {
        if (!StringUtils.isBlank(req.getCode())) {
            if (!"194711".equals(req.getCode()) || ZekeConstants.ProfilesType.PROD.equals(profilesProperties.getActive())) {
                // 校验验证码
                smsComponent.verifyPhoneCode(req.getPhoneNum(), req.getCode());
            }
        }
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.ADMIN).get();
        QueryWrapper<Agent> qw = new QueryWrapper<>();
        qw.lambda().eq(Agent::getPhoneNum, req.getPhoneNum());
        qw.lambda().notIn(Agent::getStatus, AgentConstants.AgentStatus.DEL, AgentConstants.AgentStatus.LOG_OFF);
        int count = count(qw);
        if (count > 0) {
            throw new ZekeException(400, "代理商手机号已存在");
        }
        Agent agent = new Agent();
        BeanUtils.copyProperties(req, agent);
        agent.setOperId(loginInfo.getId());
        agent.setOperName(loginInfo.getName());
        agent.setStatus(AgentConstants.AgentStatus.NORMAL);
        agent.setCreateDate(LocalDateTime.now());
        boolean flag = save(agent);
        if (!flag) {
            throw new ZekeException(400, "代理商添加失败");
        }
        Agent update = new Agent();
        update.setId(agent.getId());
        update.setInviteCode(HealthConstants.InviteCodePrefixConstants.AGENT_PREFIX + SerialNumberUtils.generatorInviteCode(agent.getId(), 5));
        flag = updateById(update);
        if (!flag) {
            throw new ZekeException(400, "代理商添加失败");
        }
        req.setAgentId(agent.getId());
        agentUserService.initAgentUser(req);
        saleInviteAgentService.bindSaleInviteAgent(req.getSaleId(), agent.getId());

    }

    /**
     * 创建代理商 h5适用
     * 1,扫码h5添加,无需登录,需要邀请码
     * 2,后台管理员添加,需要登录,需要销售人员id
     *
     * @param req
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createAgentH5(AgentCreateH5Req req) {
        Integer saleId = null;
        smsComponent.verifyPhoneCode(req.getPhoneNum(), req.getCode());
        QueryWrapper<Agent> qws = new QueryWrapper<>();
        qws.lambda().eq(Agent::getPhoneNum, req.getPhoneNum());
        qws.lambda().notIn(Agent::getStatus, AgentConstants.AgentStatus.DEL, AgentConstants.AgentStatus.LOG_OFF);
        int count = count(qws);
        if (count > 0) {
            throw new ZekeException(400, "代理商手机号已存在");
        }

        String saleName = null;
        if (!StringUtils.isBlank(req.getInviteCode())) {
            req.setInviteCode(req.getInviteCode().toUpperCase());
            QueryWrapper<AdminSaleInfo> qw = new QueryWrapper<>();
            qw.lambda().eq(AdminSaleInfo::getInviteCode, req.getInviteCode());
            qw.lambda().ne(AdminSaleInfo::getStatus, AdminConstants.SaleInfoStatus.DEL);
            qw.lambda().select(AdminSaleInfo::getAdminId, AdminSaleInfo::getName);
            AdminSaleInfo adminSaleInfo = adminSaleInfoService.getOne(qw);
            if (adminSaleInfo != null) {
                saleId = adminSaleInfo.getAdminId();
                saleName = adminSaleInfo.getName();
            } else {
                throw new ZekeException(400, "邀请码不正确");
            }
        }
        Agent agent = new Agent();
        BeanUtils.copyProperties(req, agent);
        agent.setOperId(saleId);
        agent.setOperName(saleName);
        agent.setStatus(AgentConstants.AgentStatus.NORMAL);
        agent.setCreateDate(LocalDateTime.now());
        boolean flag = save(agent);
        if (!flag) {
            throw new ZekeException(400, "代理商添加失败");
        }
        Agent update = new Agent();
        update.setId(agent.getId());
        update.setInviteCode(HealthConstants.InviteCodePrefixConstants.AGENT_PREFIX + SerialNumberUtils.generatorInviteCode(agent.getId(), 5));
        flag = updateById(update);
        if (!flag) {
            throw new ZekeException(400, "代理商添加失败");
        }
        AgentCreateReq initReq = new AgentCreateReq();
        BeanUtils.copyProperties(req, initReq);
        initReq.setAgentId(agent.getId());
        agentUserService.initAgentUser(initReq);
        if (saleId != null) {
            saleInviteAgentService.bindSaleInviteAgent(saleId, agent.getId());
        }
    }

    /**
     * 修改代理商
     *
     * @param req
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateAgent(AgentUpdateReq req) {
        if (!StringUtils.isBlank(req.getCode())) {
            if (!"194711".equals(req.getCode()) || ZekeConstants.ProfilesType.PROD.equals(profilesProperties.getActive())) {
                // 校验验证码
                smsComponent.verifyPhoneCode(req.getPhoneNum(), req.getCode());
            }
        }
        UserInterceptor.getLoginUserInfo(LoginInfo.UserType.ADMIN);
        QueryWrapper<Agent> qw = new QueryWrapper<>();
        qw.lambda().eq(Agent::getPhoneNum, req.getPhoneNum());
        qw.lambda().ne(Agent::getStatus, AgentConstants.AgentStatus.DEL);
        qw.lambda().ne(Agent::getId, req.getAgentId());
        int count = count(qw);
        if (count > 0) {
            throw new ZekeException(400, "代理商手机号已存在");
        }
        Agent agent = new Agent();
        agent.setId(req.getAgentId());
        BeanUtils.copyProperties(req, agent);
        boolean flag = updateById(agent);
        if (!flag) {
            throw new ZekeException(400, "代理商修改失败");
        }
        saleInviteAgentService.bindSaleInviteAgent(req.getSaleId(), agent.getId());

    }

    /**
     * 查询代理商列表
     *
     * @param req
     * @return
     */
    @Override
    public IPage<AgentPageRes> queryAgentPage(AgentPageReq req) {
        Assert.verifyStatusIdsParam(req.getClass(), req);
        if (StringUtils.isBlank(req.getStatus())) {
            req.setStatus(AgentConstants.AgentStatus.CAN_QUE);
        }
        if (StringUtils.isBlank(req.getOrderSort())) {
            req.setOrderSort("desc");
        }
        req.setOrderField("create_date");
        if ("-2".equals(req.getStatus())) {
            req.setOrderField("update_date");
        }
        IPage<AgentPageRes> iPage = req.pagePojo();
        iPage = getBaseMapper().queryAgentPage(iPage, req);
        return iPage;
    }

    /**
     * 查询代理商详情
     *
     * @param id
     * @return
     */
    @Override
    public AgentDetailRes queryAgentDetail(Integer id) {
        if (id == null) {
            LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.AGENT).get();
            id = loginInfo.getMechanId();
        }
        AgentDetailRes agentDetailRes = getBaseMapper().queryAgentDetail(id);
        LambdaQueryWrapper<SaleInviteAgent> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SaleInviteAgent::getAgentId, id)
                .eq(SaleInviteAgent::getStatus, 1)
                .last("limit 1");
        SaleInviteAgent saleInviteAgent = saleInviteAgentService.getOne(queryWrapper);
        if (saleInviteAgent != null && agentDetailRes != null) {
            agentDetailRes.setSaleId(saleInviteAgent.getSaleId());
            LambdaQueryWrapper<AdminSaleInfo> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(AdminSaleInfo::getAdminId, saleInviteAgent.getSaleId())
                    .eq(AdminSaleInfo::getStatus, 1);
            AdminSaleInfo adminSaleInfo = adminSaleInfoService.getOne(wrapper);
            agentDetailRes.setSaleName(adminSaleInfo.getName());
        }
        return agentDetailRes;
    }

    /**
     * 查询代理商代理医生列表 分页
     *
     * @param req
     * @return
     */
    @Override
    public IPage<AgentDoctorPageRes> queryAgentDoctorPage(AgentDoctorPageReq req) {
        Assert.verifyStatusIdsParam(req.getClass(), req);
        if (req.getAgentId() == null) {
            LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.AGENT).get();
            req.setAgentId(loginInfo.getMechanId());
        }
        IPage<AgentDoctorPageRes> iPage = req.pagePojo();
        iPage = getBaseMapper().queryAgentDoctorPage(iPage, req);
//        for (AgentDoctorPageRes item : iPage.getRecords()) {
////            switch (item.getStatus()) {
////                case UserConstants.DoctorUserStatus.NORMAL:
////                case UserConstants.DoctorUserStatus.DISABLEMECHAN:
////                case UserConstants.DoctorUserStatus.DISABLEADMIN:
////                    item.setIsAuth(1);
////                    break;
////                case UserConstants.DoctorUserStatus.TRIAL:
////                case UserConstants.DoctorUserStatus.DEL:
////                default:
////                    item.setIsAuth(0);
////            }
//        }
        return iPage;
    }

    /**
     * 查询代理商代理机构列表 分页
     *
     * @param req
     * @return
     */
    @Override
    public IPage<AgentMechanPageRes> queryAgentMechanPage(AgentMechanPageReq req) {
        if (req.getAgentId() == null) {
            LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.AGENT).get();
            req.setAgentId(loginInfo.getMechanId());
        }
        IPage<AgentMechanPageRes> iPage = req.pagePojo();
        iPage = getBaseMapper().queryAgentMechanPage(iPage, req);
        return iPage;
    }

    /**
     * 修改代理商状态
     *
     * @param id
     * @param status
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateAgentStatus(Integer id, Integer status) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.ADMIN).get();
        AgentDetailRes res = queryAgentDetail(id);
        if (res == null || res.getStatus() == AgentConstants.AgentStatus.DEL || res.getStatus() == AgentConstants.AgentStatus.LOG_OFF) {
            throw new ZekeException(400, "代理商不存在");
        }
        Agent update = new Agent();
        switch (status) {
            case AgentConstants.AgentStatus.NORMAL:
                if (res.getStatus() == AgentConstants.AgentStatus.NORMAL) {
                    return;
                }
                break;
            case AgentConstants.AgentStatus.DISABLE:
                if (res.getStatus() == AgentConstants.AgentStatus.DISABLE) {
                    return;
                }
                break;
            case AgentConstants.AgentStatus.DEL:
                if (res.getDoctorCount() > 0 || res.getMechanCount() > 0) {
                    throw new ZekeException(400, "代理商已存在邀请医生或机构无法删除,请进行注销操作");
                }
                break;
            case AgentConstants.AgentStatus.LOG_OFF:
                update.setLogOfId(loginInfo.getId());
                update.setLogOfName(loginInfo.getName());
                update.setUpdateDate(LocalDateTime.now());
                UpdateWrapper<AgentUser> uw = new UpdateWrapper<>();
                uw.lambda().eq(AgentUser::getAgentId, id);
                uw.lambda().set(AgentUser::getStatus, AgentConstants.AgentUserStatus.DEL)
                        .set(AgentUser::getUpdateDate, LocalDateTime.now());
                agentUserService.update(uw);
            default:
        }
        update.setId(id);
        update.setStatus(status);
        boolean flag = updateById(update);
        if (!flag) {
            throw new ZekeException(400, "操作失败");
        }
    }

    /**
     * 统计首页邀请机构/医生数量图
     *
     * @param req
     * @return
     */
    @Override
    public AgentCountChartStatisticsRes queryAgentCountStatistics(AgentCountChartStatisticsReq req) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo().get();
        req.setAgentId(loginInfo.getMechanId());
        if (req.verify()) {
            throw new ZekeException(400, "日期参数错误");
        }
        int type = 1;
        if (req.getStart() == null && req.getEnd() == null) {
            req.setEnd(LocalDateTime.now());
            switch (req.getFlag()) {
                case 1:
                    req.setStart(DateUtils.getFirstDayOfWeek(req.getEnd().toLocalDate()));
                    req.setSqlSegment("%c-%e");
                    break;
                case 2:
                    req.setStart(DateUtils.getFirstDayOfMonth(req.getEnd().toLocalDate()));
                    req.setSqlSegment("%c-%e");
                    break;
                case 3:
                    QueryWrapper<Agent> qw = new QueryWrapper<>();
                    qw.lambda().eq(Agent::getId, req.getAgentId());
                    qw.lambda().select(Agent::getCreateDate);
                    Agent agent = getOne(qw);
                    req.setStart(agent.getCreateDate());
                    req.setSqlSegment("%Y-%c");
                    type = 2;
                    break;
                default:
                    throw new ZekeException(400, "未知标识参数");
            }
            req.verify();
        } else {
            type = 3;
            req.setSqlSegment("%Y-%c-%e");
        }
        List<AgentCountChartStatisticsListRes> valueList;
        if (req.getIsDoctor() == 1) {
            valueList = getBaseMapper().queryAgentCountChartStatisticsListDoctor(req);
        } else {
            valueList = getBaseMapper().queryAgentCountChartStatisticsListMechan(req);
        }
        LocalDateTime start = req.getStart();
        LocalDateTime end = req.getEnd();
        LocalDateTime lastStart = null;
        LocalDateTime lastEnd = null;
        Map<String, AgentCountChartStatisticsListRes> map = valueList.stream().collect(Collectors.toMap(AgentCountChartStatisticsListRes::getKey, t -> t));
        List<AgentCountChartStatisticsListRes> tempList = new ArrayList<>();
        AgentCountChartStatisticsRes res = new AgentCountChartStatisticsRes();
        if (type == 1) {
            int max = req.getFlag() == 1 ? 7 : 31;
            for (int i = 0; i < max; i++) {
                AgentCountChartStatisticsListRes temp = new AgentCountChartStatisticsListRes();
                if (start.compareTo(LocalDateTime.now()) > 0) {
                    break;
                }
                int month = start.getMonthValue();
                int day = start.getDayOfMonth();
                AgentCountChartStatisticsListRes item = map.get(month + "-" + day);
                if (item == null) {
                    temp.setKey(month + "-" + day);
                    temp.setValue("0");
                    tempList.add(temp);
                } else {
                    tempList.add(item);
                }
                start = start.plusDays(1);
            }
            lastStart = req.getStart().minusWeeks(1);
            lastEnd = DateUtils.getLastDayOfWeek(lastStart.toLocalDate());
            if (req.getFlag() == 3) {
                lastStart = req.getStart().minusMonths(1);
                lastEnd = DateUtils.getLastDayOfMonth(lastStart.toLocalDate());
            }
        } else if (type == 2) {
            int currYear = LocalDate.now().getYear();
            while (start.compareTo(end) <= 0) {
                AgentCountChartStatisticsListRes temp = new AgentCountChartStatisticsListRes();
                int year = start.getYear();
                int month = start.getMonthValue();
                AgentCountChartStatisticsListRes item = map.get(year + "-" + month);
                if (item == null) {
                    if (currYear != year) {
                        temp.setKey(year + "年" + month + "月");
                    } else {
                        temp.setKey(month + "月");
                    }
                    temp.setValue("0");
                    tempList.add(temp);
                } else {
                    if (currYear != year) {
                        item.setKey(year + "年" + month + "月");
                    } else {
                        item.setKey(month + "月");
                    }
                    tempList.add(item);
                }
                start = start.plusMonths(1);
            }
        } else {
            int currYear = LocalDate.now().getYear();
            while (start.compareTo(end) <= 0) {
                AgentCountChartStatisticsListRes temp = new AgentCountChartStatisticsListRes();
                int year = start.getYear();
                int month = start.getMonthValue();
                int day = start.getDayOfMonth();
                AgentCountChartStatisticsListRes item = map.get(year + "-" + month + "-" + day);
                if (item == null) {
                    if (currYear != year) {
                        temp.setKey(year + "年" + month + "月" + day + "日");
                    } else {
                        temp.setKey(month + "月" + day + "日");
                    }
                    temp.setValue("0");
                    tempList.add(temp);
                } else {
                    if (currYear != year) {
                        item.setKey(year + "年" + month + "月" + day + "日");
                    } else {
                        item.setKey(month + "月" + day + "日");
                    }
                    tempList.add(item);
                }
                start = start.plusDays(1);
            }
        }
        res.setValueList(tempList);
        Integer thisCount;
        if (req.getIsDoctor() == 1) {
            thisCount = getBaseMapper().queryAgentCountChartStatisticsCountDoctor(req);
        } else {
            thisCount = getBaseMapper().queryAgentCountChartStatisticsCountMechan(req);
        }
        res.setThisCount(thisCount == null ? 0 : thisCount);
        if (lastStart != null && lastEnd != null) {
            req.setStart(lastStart);
            req.setEnd(lastEnd);
            Integer lastCount;
            if (req.getIsDoctor() == 1) {
                lastCount = getBaseMapper().queryAgentCountChartStatisticsCountDoctor(req);
            } else {
                lastCount = getBaseMapper().queryAgentCountChartStatisticsCountMechan(req);
            }
            res.setLastCount(lastCount == null ? 0 : lastCount);
            if (res.getThisCount() == 0 && res.getLastCount() == 0) {
                res.setGrowthRate(0);
            } else if (res.getThisCount() > 0 && res.getLastCount() == 0) {
                res.setGrowthRate(100);
            } else {
                res.setGrowthRate((int) (BigDecimalUtils.divide(res.getThisCount(), res.getLastCount()).doubleValue() * 100));
            }
        }
        return res;
    }

    /**
     * 初始化代理商邀请码
     */
    @Override
    public void initAgentInviteCode() {
        QueryWrapper<Agent> qw = new QueryWrapper<>();
        qw.lambda().isNull(Agent::getInviteCode);
        qw.lambda().select(Agent::getId);
        List<Agent> list = list(qw);
        for (Agent item : list) {
            item.setInviteCode(HealthConstants.InviteCodePrefixConstants.AGENT_PREFIX + SerialNumberUtils.generatorInviteCode(item.getId(), 5));
        }
        updateBatchById(list);
    }
}
